/**
 *
 */
package top.ibase4j.core.base;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.ModelMap;

import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.fastjson.JSON;
import com.weibo.api.motan.config.ProtocolConfig;
import com.weibo.api.motan.config.RefererConfig;

import top.ibase4j.core.config.RpcConfig;
import top.ibase4j.core.support.Pagination;
import top.ibase4j.core.support.context.ApplicationContextHolder;
import top.ibase4j.core.support.http.HttpCode;
import top.ibase4j.core.support.http.SessionUser;
import top.ibase4j.core.util.InstanceUtil;
import top.ibase4j.core.util.WebUtil;

/**
 * 控制器基类
 *
 * @author ShenHuaJie
 * @version 2016年5月20日 下午3:47:58
 */
public abstract class AbstractController implements InitializingBean {
    protected Logger logger = LogManager.getLogger();
    private static final Map<String, Object> serviceFactory = InstanceUtil.newHashMap();
    private static final RpcConfig.EnableDubboReference enableDubbo = new RpcConfig.EnableDubboReference();
    private static final RpcConfig.EnableMotan enableMotan = new RpcConfig.EnableMotan();
    private static ApplicationConfig dubboApplication;
    private static RegistryConfig dubboRegistry;
    private static ProtocolConfig motanProtocol;
    private static com.weibo.api.motan.config.RegistryConfig motanRegistry;

    @Override
    public void afterPropertiesSet() throws Exception {
        Field[] fields = getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            Object v = field.get(this);
            Class<?> cls = field.getType();
            if (v == null && cls.getSimpleName().toLowerCase().contains("service")) {
                v = getService(cls);
                field.set(this, v);
            }
            field.setAccessible(false);
        }
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    protected Object getService(Class<?> cls) {
        String clsName = cls.getName();
        Object v = serviceFactory.get(clsName);
        if (v == null) {
            synchronized (clsName) {
                v = serviceFactory.get(clsName);
                if (v == null) {
                    logger.info("*****Autowire {}*****", cls);
                    if (enableDubbo.matches(null, null)) {
                        if (dubboApplication == null || dubboRegistry == null) {
                            synchronized (AbstractController.class) {
                                if (dubboApplication == null) {
                                    dubboApplication = ApplicationContextHolder.getBean(ApplicationConfig.class);
                                }
                                if (dubboRegistry == null) {
                                    dubboRegistry = ApplicationContextHolder.getBean(RegistryConfig.class);
                                }
                            }
                        }
                        // 引用远程服务
                        ReferenceConfig<?> reference = new ReferenceConfig<>();
                        reference.setApplication(dubboApplication);
                        reference.setRegistry(dubboRegistry); // 多个注册中心可以用setRegistries()
                        reference.setInterface(cls);
                        v = reference.get();
                    } else if (enableMotan.matches(null, null)) {
                        if (motanProtocol == null || motanRegistry == null) {
                            synchronized (AbstractController.class) {
                                if (motanProtocol == null) {
                                    motanProtocol = ApplicationContextHolder.getBean(ProtocolConfig.class);
                                }
                                if (motanRegistry == null) {
                                    motanRegistry = ApplicationContextHolder
                                            .getBean(com.weibo.api.motan.config.RegistryConfig.class);
                                }
                            }
                        }
                        // 引用远程服务
                        RefererConfig reference = new RefererConfig<>();
                        reference.setProtocol(motanProtocol);
                        reference.setRegistry(motanRegistry); // 多个注册中心可以用setRegistries()
                        reference.setInterface(cls);
                        v = reference.getRef();
                    } else {
                        v = ApplicationContextHolder.getBean(cls);
                    }
                    logger.info("*****{} Autowired*****", cls);
                    serviceFactory.put(clsName, v);
                }
            }
        }
        return v;
    }

    /** 获取当前用户Id(shiro) */
    protected SessionUser getCurrUser() {
        return (SessionUser)SecurityUtils.getSubject().getPrincipal();
    }

    /** 获取当前用户Id */
    protected Long getCurrUser(HttpServletRequest request) {
        SessionUser user = WebUtil.getCurrentUser(request);
        if (user == null) {
            return null;
        } else {
            return user.getId();
        }
    }

    /** 设置成功响应代码 */
    protected ResponseEntity<ModelMap> setSuccessModelMap() {
        return setSuccessModelMap(new ModelMap(), null);
    }

    /** 设置成功响应代码 */
    protected ResponseEntity<ModelMap> setSuccessModelMap(ModelMap modelMap) {
        return setSuccessModelMap(modelMap, null);
    }

    /** 设置成功响应代码 */
    protected ResponseEntity<ModelMap> setSuccessModelMap(Object data) {
        return setModelMap(new ModelMap(), HttpCode.OK, data);
    }

    /** 设置成功响应代码 */
    protected ResponseEntity<ModelMap> setSuccessModelMap(ModelMap modelMap, Object data) {
        return setModelMap(modelMap, HttpCode.OK, data);
    }

    /** 设置响应代码 */
    protected ResponseEntity<ModelMap> setModelMap(HttpCode code) {
        return setModelMap(new ModelMap(), code, null);
    }

    /** 设置响应代码 */
    protected ResponseEntity<ModelMap> setModelMap(String code, String msg) {
        return setModelMap(new ModelMap(), code, msg, null);
    }

    /** 设置响应代码 */
    protected ResponseEntity<ModelMap> setModelMap(ModelMap modelMap, HttpCode code) {
        return setModelMap(modelMap, code, null);
    }

    /** 设置响应代码 */
    protected ResponseEntity<ModelMap> setModelMap(HttpCode code, Object data) {
        return setModelMap(new ModelMap(), code, data);
    }

    /** 设置响应代码 */
    protected ResponseEntity<ModelMap> setModelMap(String code, String msg, Object data) {
        return setModelMap(new ModelMap(), code, msg, data);
    }

    /** 设置响应代码 */
    protected ResponseEntity<ModelMap> setModelMap(ModelMap modelMap, HttpCode code, Object data) {
        return setModelMap(modelMap, code.value().toString(), code.msg(), data);
    }

    /** 设置响应代码 */
    protected ResponseEntity<ModelMap> setModelMap(ModelMap modelMap, String code, String msg, Object data) {
        if (!modelMap.isEmpty()) {
            Map<String, Object> map = InstanceUtil.newLinkedHashMap();
            map.putAll(modelMap);
            modelMap.clear();
            for (String key : map.keySet()) {
                if (!key.startsWith("org.springframework.validation.BindingResult") && !key.equals("void")) {
                    modelMap.put(key, map.get(key));
                }
            }
        }
        if (data != null) {
            if (data instanceof Pagination<?>) {
                Pagination<?> page = (Pagination<?>)data;
                modelMap.put("rows", page.getRecords());
                modelMap.put("current", page.getCurrent());
                modelMap.put("size", page.getSize());
                modelMap.put("pages", page.getPages());
                modelMap.put("total", page.getTotal());
            } else if (data instanceof List<?>) {
                modelMap.put("rows", data);
                modelMap.put("total", ((List<?>)data).size());
            } else {
                modelMap.put("data", data);
            }
        }
        modelMap.put("code", code);
        modelMap.put("msg", msg);
        modelMap.put("timestamp", System.currentTimeMillis());
        logger.info("response===>{}", JSON.toJSONString(modelMap));
        return ResponseEntity.ok(modelMap);
    }
}
